﻿using Dapper.Contrib.Extensions;
using DapperExtensions.Sql;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;

namespace DapperExtensions
{
    public class DataBaseUtility
    {
        private static object _objLock = new object();
        private static string _defaultConnName = null;
        private string _connName = string.Empty;
        private string _connString = string.Empty;
        private string _providerName = string.Empty;
        private DbProviderFactory _providerFactory;
        private static Dictionary<string, DataBaseUtility> _dictConnHelper = new Dictionary<string, DataBaseUtility>();

        public static string DefaultConnName
        {
            get
            {
                if(string.IsNullOrEmpty(DataBaseUtility._defaultConnName))
                {
                    DataBaseUtility.setDefaultConnName();
                }
                return DataBaseUtility._defaultConnName;
            }
            set
            {
                DataBaseUtility._defaultConnName = value;
            }
        }

        public static DataBaseUtility Default
        {
            get
            {
                if(string.IsNullOrEmpty(DataBaseUtility.DefaultConnName))
                {
                    throw new Exception("没有配置默认连接信息");
                }
                return DataBaseUtility.GetInstance(DataBaseUtility.DefaultConnName);
            }
        }

        public static IDbConnection DefaultConnection
        {
            get
            {
                return DataBaseUtility.Default.GetConnection();
            }
        }

        public DbProviderFactory ProviderFactory
        {
            get
            {
                return this._providerFactory;
            }
        }

        public string ConnString
        {
            get
            {
                return this._connString;
            }
        }

        public string ProvideName
        {
            get
            {
                if(string.IsNullOrEmpty(this._providerName))
                {
                    this._providerName = "System.Data.OracleClient";
                }
                return this._providerName;
            }
        }

        private static void setDefaultConnName()
        {
            if(!string.IsNullOrEmpty(ConfigurationManager.AppSettings["default_conn_name"]))
            {
                DataBaseUtility.DefaultConnName = ConfigurationManager.AppSettings["default_conn_name"];
                return;
            }
            DataBaseUtility.DefaultConnName = "default";
        }

        public DataBaseUtility()
        {
        }

        public DataBaseUtility(string connName)
        {
            this._connName = connName;
            this._connString = ConfigurationManager.ConnectionStrings[this._connName].ConnectionString;
            this.init();
        }

        public DataBaseUtility(string connName, string connString)
        {
            this._connName = connName;
            if(string.IsNullOrEmpty(connString))
            {
                this._connString = ConfigurationManager.ConnectionStrings[this._connName].ConnectionString;
            }
            else
            {
                this._connString = connString;
            }
            this.init();
        }

        private void init()
        {
            if(string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[this._connName].ProviderName))
            {
                this._providerName = "System.Data.OracleClient";
            }
            else
            {
                this._providerName = ConfigurationManager.ConnectionStrings[this._connName].ProviderName;
            }
            this._providerFactory = DbProviderFactories.GetFactory(this._providerName);
        }

        public static DataBaseUtility GetInstanceDefault(string connString)
        {
            string text = "default";
            if(!DataBaseUtility._dictConnHelper.ContainsKey(text))
            {
                object objLock;
                Monitor.Enter(objLock = DataBaseUtility._objLock);
                try
                {
                    if(!DataBaseUtility._dictConnHelper.ContainsKey(text))
                    {
                        DataBaseUtility value = new DataBaseUtility(text, connString);
                        DataBaseUtility._dictConnHelper.Add(text, value);
                    }
                }
                finally
                {
                    Monitor.Exit(objLock);
                }
            }
            return DataBaseUtility._dictConnHelper[text];
        }

        public static DataBaseUtility GetInstance(string connName)
        {
            if(!DataBaseUtility._dictConnHelper.ContainsKey(connName))
            {
                object objLock;
                Monitor.Enter(objLock = DataBaseUtility._objLock);
                try
                {
                    if(!DataBaseUtility._dictConnHelper.ContainsKey(connName))
                    {
                        DataBaseUtility value = new DataBaseUtility(connName);
                        DataBaseUtility._dictConnHelper.Add(connName, value);
                    }
                }
                finally
                {
                    Monitor.Exit(objLock);
                }
            }
            return DataBaseUtility._dictConnHelper[connName];
        }

        public static DataBaseUtility GetInstance(string connName, string connStr)
        {
            if(!DataBaseUtility._dictConnHelper.ContainsKey(connName))
            {
                object objLock;
                Monitor.Enter(objLock = DataBaseUtility._objLock);
                try
                {
                    if(!DataBaseUtility._dictConnHelper.ContainsKey(connName))
                    {
                        DataBaseUtility value = new DataBaseUtility(connName, connStr);
                        DataBaseUtility._dictConnHelper.Add(connName, value);
                    }
                }
                finally
                {
                    Monitor.Exit(objLock);
                }
            }
            return DataBaseUtility._dictConnHelper[connName];
        }

        public IDbConnection GetConnection()
        {
            IDbConnection dbConnection = this.ProviderFactory.CreateConnection();
            dbConnection.ConnectionString = this.ConnString;
            return dbConnection;
        }

        public static void CloseConnection(IDbConnection conn)
        {
            if(conn != null)
            {
                conn.Close();
                conn.Dispose();
                conn = null;
            }
        }

        private static Regex regex = new Regex("[@:\\.\\-;,'\\\\\"]");

        public static string FilterCharForSql(string source)
        {
            if(string.IsNullOrEmpty(source))
                return string.Empty;

            return regex.Replace(source, string.Empty);
        }
        public static string GetTableName(Type type)
        {
            string name = string.Empty;
            var tableAttrName =
                type.GetCustomAttribute<TableAttribute>(false)?.Name
                ?? (type.GetCustomAttributes(false).FirstOrDefault(attr => attr.GetType().Name == "TableAttribute") as dynamic)?.Name;

            if (tableAttrName != null)
            {
                name = tableAttrName;
            }
            else
            {
                name = type.Name + "s";
                if (type.IsInterface && name.StartsWith("I"))
                    name = name.Substring(1);
            }
            return name;
        }
    }
}